// Sprite Scene Node
// (c) jimon game studio

#include "CSpriteSceneNode.h"
#include "IResourceManager.h"

namespace je
{
	namespace scene
	{
		//! Constructor
		CSpriteSceneNode::CSpriteSceneNode(video::IRender * Render,scene::ISceneManager * SceneManager)
			:ISpriteSceneNode(Render,"SpriteSceneNode"),CurrentSceneManager(SceneManager),LastFrame(0),CurrentFrame(0)
		{
			SpriteCorrectionSize.SetXYZ(1,1,1);
		}

		//! Destructor
		CSpriteSceneNode::~CSpriteSceneNode()
		{
			SetMaterialResource(NULL);
		}

		//! Set Frame
		void CSpriteSceneNode::SetFrame(s32 Frame)
		{
			CurrentFrame = Frame;
		}

		//! Get Frame
		s32 CSpriteSceneNode::GetFrame()
		{
			return CurrentFrame;
		}

		//! Get Frame Count
		s32 CSpriteSceneNode::GetFrameCount()
		{
			if(CurrentSharedMaterial)
				return CurrentSharedMaterial->GetTexture(0)->GetCount();
			else
				return 0;
		}

		//! Set Material Resource
		void CSpriteSceneNode::SetMaterialResource(media::jeMaterialResource * MaterialResource,u1 UseUniqueMaterial,u1 UseUniqueTextures,u1 UseUniqueShader)
		{
			if(CurrentSharedMaterial)
				CurrentSceneManager->UnRegisterNodeFromRenderingQueue(this,CurrentSharedMaterial->GetMaterial());

			LastFrame = 0;
			CurrentFrame = 0;

			IMaterialResourceNode::SetMaterialResource(MaterialResource,UseUniqueMaterial,UseUniqueTextures,UseUniqueShader);

			if(MaterialResource)
			{
				CurrentSceneManager->RegisterNodeInRenderingQueue(this,CurrentSharedMaterial->GetMaterial());

				jeVector2di FrameSize = CurrentSharedMaterial->GetTexture(0)->GetFrameSize();
				SpriteSize.SetXYZ((f32)FrameSize.X,(f32)FrameSize.Y,1);
			}

			NeedToRebuildMatrix = true;
		}

		//! On Update
		void CSpriteSceneNode::OnUpdate()
		{
			if(CurrentFrame != LastFrame)
			{
				CurrentSharedMaterial->GetMaterial()->SetTexture(CurrentSharedMaterial->GetTexture(0)->Get()[CurrentFrame]);
				LastFrame = CurrentFrame;
			}

			ISceneNode::OnUpdate();
		}

		//! On Render
		void CSpriteSceneNode::OnRender()
		{
			CurrentRender->SetMatrix(SpriteAbsoluteModelMatrix,video::RMT_MODEL);
			CurrentRender->SetMatrix(TextureMatrix,video::RMT_TEXTURE);
			CurrentRender->SetMaterial(CurrentSharedMaterial->GetMaterial());
			CurrentRender->RenderOperation(video::ROT_DRAW_QUAD);

			ISceneNode::OnRender();
		}

		//! On Visibility Culling
		void CSpriteSceneNode::OnVisibilityCulling()
		{
			f32 SpriteRadius = jeSqr(2.0f) * SpriteCorrectionSize.GetMaxComponent() * AbsoluteScale.GetMaxComponent();
			InFrame = CurrentSceneManager->GetCurrentCamera()->GetFrustum()->IsSphereIn(SpriteAbsoluteModelMatrix.GetTranslation(),SpriteRadius);
			ISceneNode::OnVisibilityCulling();
		}

		//! Rebuild Transformations
		void CSpriteSceneNode::RebuildTransformations()
		{
			if(NeedToRebuildMatrix)
			{
				ModelMatrix.Identity();
				ModelMatrix.Scale(CurrentScale);
				ModelMatrix.Rotate(CurrentRotation);
				ModelMatrix.Translate(CurrentPosition);

				switch(CurrentSceneManager->GetCurrentCamera()->GetCameraOptions().CurrentMode)
				{
				case ICameraSceneNode::CM_2D:
					SpriteCorrectionSize = SpriteSize;
					break;
				case ICameraSceneNode::CM_3D:
					{
						jeVector2df Temp(SpriteSize.X,SpriteSize.Y);
						Temp = Temp / jeMax(SpriteSize.X,SpriteSize.Y);
						SpriteCorrectionSize.SetXYZ(Temp.X,Temp.Y,1);
						break;
					}
				};

				SpriteMatrix.Identity();
				SpriteMatrix.Scale(SpriteCorrectionSize * CurrentScale);
				SpriteMatrix.Rotate(CurrentRotation);
				SpriteMatrix.Translate(CurrentPosition);
				NeedToRebuildMatrix = false;
			}
		}

		//! Build Absolute Model Matrix
		void CSpriteSceneNode::BuildAbsoluteModelMatrix(const jeMatrix4f & ParentMatrix,const jeVector3df & ParentScale,u1 Changed)
		{
			ISceneNode::BuildAbsoluteModelMatrix(ParentMatrix,ParentScale,Changed);
			SpriteAbsoluteModelMatrix = ParentMatrix * SpriteMatrix;
		}

		//! Serialize
		void CSpriteSceneNode::Serialize(core::ISerializeStream * SerializeStream)
		{
			JE_SS_BEGIN(SpriteSceneNode)
			JE_SS(CurrentFrame)
			JE_SS_END(SpriteSceneNode)

			if(JE_SS_LOAD)
				OnUpdate();

			IMaterialResourceNode::Serialize(SerializeStream);
		}

	}
}
